package com.university.mentalhealthplatform.global.log.login;

import com.university.mentalhealthplatform.global.rbac.dto.request.AuthRequest;
import com.university.mentalhealthplatform.global.rbac.model.User;
import com.university.mentalhealthplatform.global.rbac.service.entity.BaseUserService;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

@Aspect
@Component
public class LoginLogAspect {

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private LoginLogRepository loginLogRepository;

    @Autowired
    private BaseUserService baseUserService;

    // 定义切点：匹配带有 @LoginLogAction 注解的方法
    @Pointcut("@annotation(com.university.mentalhealthplatform.global.log.login.LoginLogAction)")
    public void loginLogActionPointcut() {}

    // 环绕通知：记录登录日志并处理异常
    @Around("loginLogActionPointcut()")
    public Object logLoginOperation(ProceedingJoinPoint joinPoint) throws Throwable {
        LoginLog loginLog = new LoginLog();
        loginLog.setLoginTime(LocalDateTime.now());

        // 获取 IP 地址
        String ipAddress = request.getRemoteAddr();
        loginLog.setLoginAddress(ipAddress);

        // 获取方法签名和注解信息
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        LoginLogAction loginLogAction = signature.getMethod().getAnnotation(LoginLogAction.class);
        loginLog.setLoginMessage(loginLogAction.description());

        loginLog.setBrowser("Edge");
        loginLog.setLoginLocation("成都");
        loginLog.setOperatingSystem("Windows");

        String userName = null;
        User user = null;

        try {
            // 尝试获取用户名
            Object[] args = joinPoint.getArgs();
            if (args != null && args.length > 0 && args[0] instanceof AuthRequest authRequest) {
                userName = authRequest.getUsername();
                loginLog.setLoginName(userName);
            } else {
                loginLog.setLoginName("Unknown");
                // 如果无法获取用户名，记录为异常并返回
                loginLog.setLoginStatus("EXCEPTION");
                loginLog.setLoginMessage("获取用户名失败：" + userName);
                loginLogRepository.save(loginLog);
                return buildErrorResponse("UNAUTHORIZED", "用户名或密码错误", HttpStatus.UNAUTHORIZED, null);
            }

            // 执行目标方法并捕获返回值
            Object result = joinPoint.proceed();

            // 尝试根据用户名查找用户对象
            user = baseUserService.findByUsername(userName).orElse(null);

            if (user != null) {
                loginLog.setUser(user);
                loginLog.setLoginStatus("SUCCESS");
                loginLog.setLoginMessage("登录成功");
            } else {
                // 如果无法找到用户，记录为异常
                loginLog.setLoginStatus("EXCEPTION");
                loginLog.setLoginMessage("无法找到用户：" + userName);
            }

            // 保存登录日志
            loginLogRepository.save(loginLog);
            return result;

        } catch (Throwable throwable) {
            // 处理登录失败
            loginLog.setLoginStatus("EXCEPTION");
            loginLog.setLoginMessage("异常: " + throwable.getMessage());
            loginLogRepository.save(loginLog);

            // 返回处理异常后的错误响应
            return handleLoginException(throwable, loginLog);
        }
    }

    // 异常处理逻辑
    private Object handleLoginException(Throwable throwable, LoginLog loginLog) throws Throwable {
        // 设置失败状态
        loginLog.setLoginStatus("FAILURE");

        if (throwable instanceof BadCredentialsException) {
            // 用户认证失败
            loginLog.setLoginMessage("UNAUTHORIZED: 用户名或密码错误");
            loginLogRepository.save(loginLog);

            return buildErrorResponse(
                    "UNAUTHORIZED",
                    "用户名或密码错误",
                    HttpStatus.UNAUTHORIZED,
                    null
            );

        } else {
            // 其他异常
            loginLog.setLoginMessage("INTERNAL_SERVER_ERROR: " + throwable.getMessage());
            loginLogRepository.save(loginLog);

            return buildErrorResponse(
                    "INTERNAL_SERVER_ERROR",
                    "服务器内部错误",
                    HttpStatus.INTERNAL_SERVER_ERROR,
                    null
            );
        }
    }

    // 构建错误响应
    private ResponseEntity<Map<String, Object>> buildErrorResponse(
            String code, String message, HttpStatus status, BindingResult bindingResult) {

        Map<String, Object> response = new HashMap<>();
        response.put("code", code);
        response.put("message", message);
        response.put("status", status.value());
        response.put("timestamp", System.currentTimeMillis());

        // 添加校验错误详细信息（如果存在）
        if (bindingResult != null && bindingResult.hasErrors()) {
            response.put("errors", bindingResult.getFieldErrors().stream()
                    .map(error -> Map.of(
                            "field", error.getField(),
                            "message", error.getDefaultMessage()))
                    .toList());
        }

        return ResponseEntity.status(status).body(response);
    }
}
